package site.edody.dframe.plugin;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 动态依赖管理器 - 通过代码配置依赖
 */

public class CodeBasedDependencyManager {
    private final Path cacheDir;
    private final List<String> repositories;
    private final Map<String, Dependency> dependencies;
    private URLClassLoader classLoader;

    private static final Logger log = LoggerFactory.getLogger(CodeBasedDependencyManager.class);
    
    // 单例实例
    private static CodeBasedDependencyManager instance;

    /**
     * 私有构造函数
     */
    private CodeBasedDependencyManager(String[] mavenurls) {

        this.cacheDir =  Paths.get(".dynamic-deps-cache");
        this.repositories = new ArrayList<>();
        this.dependencies = new ConcurrentHashMap<>();
        if ( mavenurls != null && mavenurls.length > 0){
            repositories.addAll(Arrays.asList(mavenurls));
        } else {
            // 添加默认的Maven中央仓库
            repositories.add("https://repo1.maven.org/maven2/");
            repositories.add("https://jcenter.bintray.com/");
        }
        // 确保缓存目录存在
        ensureCacheDirectory();
    }

    /**
     * 获取单例实例
     */
    public static synchronized CodeBasedDependencyManager getInstance(String[] mavenurls) {
        if (instance == null) {
            instance = new CodeBasedDependencyManager( mavenurls);
        }
        return instance;
    }

    /**
     * 添加仓库地址
     */
    public void addRepository(String repositoryUrl) {
        if (!repositoryUrl.endsWith("/")) {
            repositoryUrl += "/";
        }
        repositories.add(repositoryUrl);
    }

    /**
     * 添加依赖
     */
    public void addDependency(String groupId, String artifactId, String version) {
        addDependency(groupId, artifactId, version, null);
    }

    /**
     * 添加依赖（指定仓库）
     */
    public void addDependency(String groupId, String artifactId, String version, String repository) {
        Dependency dep = new Dependency(groupId, artifactId, version, repository);
        dependencies.put(dep.getKey(), dep);
    }

    /**
     * 批量添加依赖
     */
    public void addDependencies(List<DependencyInfo> dependencyList) {
        for (DependencyInfo info : dependencyList) {
            addDependency(info.groupId, info.artifactId, info.version, info.repository);
        }
    }

    /**
     * 移除依赖
     */
    public void removeDependency(String groupId, String artifactId, String version) {
        String key = Dependency.createKey(groupId, artifactId, version);
        dependencies.remove(key);
    }

    /**
     * 清空所有依赖
     */
    public void clearDependencies() {
        dependencies.clear();
    }

    /**
     * 加载所有依赖
     */
    public void loadDependencies() throws DependencyResolutionException {
        List<URL> jarUrls = new ArrayList<>();
        List<DependencyResolutionException> errors = new ArrayList<>();

        for (Dependency dep : dependencies.values()) {
            try {
                URL jarUrl = resolveDependency(dep);
                jarUrls.add(jarUrl);
                log.info("已解析依赖: " + dep);
            } catch (DependencyResolutionException e) {
                errors.add(e);
                log.error("解析依赖失败: " + dep + ", 错误: " + e.getMessage());
            }
        }

        // 如果有错误，抛出聚合异常
        if (!errors.isEmpty()) {
            throw new DependencyResolutionException("部分依赖解析失败", errors);
        }

        // 创建类加载器
        classLoader = new URLClassLoader(
                jarUrls.toArray(new URL[0]),
                getClass().getClassLoader()
        );
    }

    /**
     * 解析单个依赖
     */
    private URL resolveDependency(Dependency dep) throws DependencyResolutionException {
        // 检查缓存中是否已存在
        Path cachedJar = getCachedJarPath(dep);
        if (Files.exists(cachedJar)) {
            try {
                log.info("使用缓存中的依赖: " + dep);
                return cachedJar.toUri().toURL();
            } catch (MalformedURLException e) {
                throw new DependencyResolutionException("无效的缓存JAR路径: " + cachedJar, e);
            }
        }

        // 尝试从配置的仓库下载
        List<String> repoList = new ArrayList<>();
        if (dep.getRepository() != null) {
            repoList.add(dep.getRepository());
        }
        repoList.addAll(repositories);

        DependencyResolutionException lastException = null;
        for (String repoUrl : repoList) {
            try {
                URL jarUrl = buildDependencyUrl(repoUrl, dep);
                return downloadFromUrl(jarUrl, cachedJar);
            } catch (DependencyResolutionException e) {
                lastException = e;
                log.error("从仓库 " + repoUrl + " 下载失败: " + e.getMessage());
            }
        }

        throw new DependencyResolutionException(
                "无法从任何仓库下载依赖: " + dep, lastException);
    }

    /**
     * 从URL下载文件到缓存
     */
    private URL downloadFromUrl(URL sourceUrl, Path targetPath) throws DependencyResolutionException {
        log.info("正在下载: " + sourceUrl);

        try {
            // 创建父目录
            Files.createDirectories(targetPath.getParent());

            // 下载文件
            try (InputStream in = sourceUrl.openStream()) {
                Files.copy(in, targetPath, StandardCopyOption.REPLACE_EXISTING);
            }

            return targetPath.toUri().toURL();
        } catch (IOException e) {
            throw new DependencyResolutionException("下载依赖失败: " + sourceUrl, e);
        }
    }

    /**
     * 构建依赖的下载URL
     */
    private URL buildDependencyUrl(String repoUrl, Dependency dep) throws DependencyResolutionException {
        try {
            if (!repoUrl.endsWith("/")) {
                repoUrl += "/";
            }

            String path = String.format("%s/%s/%s/%s-%s.jar",
                    dep.getGroupId().replace('.', '/'),
                    dep.getArtifactId(),
                    dep.getVersion(),
                    dep.getArtifactId(),
                    dep.getVersion());

            return new URL(repoUrl + path);
        } catch (MalformedURLException e) {
            throw new DependencyResolutionException("构建依赖URL失败: " + dep, e);
        }
    }

    /**
     * 获取缓存的JAR路径
     */
    private Path getCachedJarPath(Dependency dep) {
        String fileName = String.format("%s-%s-%s.jar",
                dep.getGroupId(), dep.getArtifactId(), dep.getVersion());
        return cacheDir.resolve(fileName);
    }

    /**
     * 确保缓存目录存在
     */
    private void ensureCacheDirectory() {
        if (!Files.exists(cacheDir)) {
            try {
                Files.createDirectories(cacheDir);
                log.info("创建缓存目录: " + cacheDir);
            } catch (IOException e) {
                throw new RuntimeException("无法创建缓存目录: " + cacheDir, e);
            }
        }
    }

    /**
     * 使用类加载器加载类
     */
    public Class<?> loadClass(String className) throws ClassNotFoundException {
        if (classLoader == null) {
            throw new IllegalStateException("请先调用 loadDependencies() 方法");
        }

        try {
            // 首先尝试直接加载
            return classLoader.loadClass(className);
        } catch (ClassNotFoundException e) {
            // 如果找不到，尝试将最后一个点转换为$（处理内部类）
            int lastDotIndex = className.lastIndexOf('.');
            if (lastDotIndex != -1) {
                String innerClassName = className.substring(0, lastDotIndex) + "$" +
                        className.substring(lastDotIndex + 1);
                try {
                    return classLoader.loadClass(innerClassName);
                } catch (ClassNotFoundException e2) {
                    // 如果内部类格式也找不到，抛出原始异常
                    throw e;
                }
            }
            throw e;
        }
    }

    /**
     * 获取类加载器
     */
    public ClassLoader getClassLoader() {
        return classLoader;
    }

    /**
     * 获取缓存目录
     */
    public Path getCacheDir() {
        return cacheDir;
    }

    /**
     * 清空缓存
     */
    public void clearCache() throws IOException {
        if (Files.exists(cacheDir)) {
            Files.walk(cacheDir)
                    .sorted(Comparator.reverseOrder())
                    .forEach(path -> {
                        try {
                            Files.deleteIfExists(path);
                        } catch (IOException e) {
                            log.error("无法删除文件: " + path + ", 错误: " + e.getMessage());
                        }
                    });
            log.info("已清空缓存目录: " + cacheDir);
        }
    }

    /**
     * 依赖项内部表示
     */
    private static class Dependency {
        private final String groupId;
        private final String artifactId;
        private final String version;
        private final String repository;

        public Dependency(String groupId, String artifactId, String version, String repository) {
            this.groupId = groupId;
            this.artifactId = artifactId;
            this.version = version;
            this.repository = repository;
        }

        public static String createKey(String groupId, String artifactId, String version) {
            return groupId + ":" + artifactId + ":" + version;
        }

        public String getKey() {
            return createKey(groupId, artifactId, version);
        }

        public String getGroupId() { return groupId; }
        public String getArtifactId() { return artifactId; }
        public String getVersion() { return version; }
        public String getRepository() { return repository; }

        @Override
        public String toString() {
            return getKey();
        }
    }

    /**
     * 依赖信息传输对象
     */
    public static class DependencyInfo {
        public final String groupId;
        public final String artifactId;
        public final String version;
        public final String repository;

        public DependencyInfo(String groupId, String artifactId, String version) {
            this(groupId, artifactId, version, null);
        }

        public DependencyInfo(String groupId, String artifactId, String version, String repository) {
            this.groupId = groupId;
            this.artifactId = artifactId;
            this.version = version;
            this.repository = repository;
        }
    }

    /**
     * 依赖解析异常
     */
    public static class DependencyResolutionException extends Exception {
        private final List<DependencyResolutionException> subExceptions;

        public DependencyResolutionException(String message) {
            super(message);
            this.subExceptions = Collections.emptyList();
        }

        public DependencyResolutionException(String message, Throwable cause) {
            super(message, cause);
            this.subExceptions = Collections.emptyList();
        }

        public DependencyResolutionException(String message, List<DependencyResolutionException> subExceptions) {
            super(message);
            this.subExceptions = subExceptions != null ?
                    new ArrayList<>(subExceptions) : Collections.emptyList();
        }

        public List<DependencyResolutionException> getSubExceptions() {
            return Collections.unmodifiableList(subExceptions);
        }

        public void printAllExceptions() {
            log.error(getMessage());
            for (DependencyResolutionException subEx : subExceptions) {
                log.error("  - " + subEx.getMessage());
                if (subEx.getCause() != null) {
                    log.error("    原因: " + subEx.getCause().getMessage());
                }
            }
        }
    }
}